﻿#region --- License & Copyright Notice ---
/*
ConsoleFx CommandLine Processing Library

Copyright (c) 2006-2012 Jeevan James
All rights reserved.

The contents of this file are made available under the terms of the
Eclipse Public License v1.0 (the "License") which accompanies this
distribution, and is available at the following URL:
http://opensource.org/licenses/eclipse-1.0.txt

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
the specific language governing rights and limitations under the License.

By using this software in any fashion, you are agreeing to be bound by the
terms of the License.
*/
#endregion

using System;
using System.Collections.Generic;

using ConsoleFx.Resources;

namespace ConsoleFx.Programs.Complex
{
    public sealed class ConsoleProgram : ConsoleProgramBase
    {
        //The function that will be called to decide the application's context, after processing all
        //the command-line inputs
        private readonly ContextSelector _contextSelector;

        //Mapping of contexts to their corresponding handlers
        private readonly Dictionary<string, ExecuteHandler> _handlerMappings = new Dictionary<string, ExecuteHandler>();

        private bool _showHelp;

        public ConsoleProgram(ContextSelector contextSelector, bool includeHelpSupport = false,
            CommandGrouping commandGrouping = CommandGrouping.DoesNotMatter, bool displayUsageOnError = true)
        {
            if (contextSelector == null)
                throw new ArgumentNullException("contextSelector");
            _contextSelector = contextSelector;
            if (includeHelpSupport)
                IncludeHelpSupport();
            Properties.Behavior.Grouping = commandGrouping;
            Properties.Behavior.DisplayUsageOnError = displayUsageOnError;
        }

        public int Run()
        {
            try
            {
                string[] commandlineArgs = Environment.GetCommandLineArgs();
                Parse(commandlineArgs);

                if (string.IsNullOrEmpty(Properties.Context))
                    throw new ConsoleProgramException(ConsoleProgramException.Codes.ContextNotAvailable,
                        ConsoleProgramMessages.ContextNotAvailable);

                //int exitCode = Properties.Context == ProgramContext.Help ? HelpHandler() : _normalHandler();
                int exitCode = 0;
                return exitCode;
            }
            catch (Exception ex)
            {
                return HandleError(ex);
            }
        }

        public void RegisterContext(string context, ExecuteHandler handler)
        {
            _handlerMappings.Add(context, handler);
        }

        public ComplexArgument AddArgument(bool optional = false)
        {
            var argument = new ComplexArgument {
                IsOptional = optional
            };
            return argument;
        }

        public ComplexOption AddOption(string name, string shortName = null, bool caseSensitive = false, int order = int.MaxValue)
        {
            var option = new ComplexOption(name) {
                CaseSensitive = caseSensitive,
                Order = order,
            };
            if (!string.IsNullOrWhiteSpace(shortName))
                option.ShortName = shortName;

            return option;
        }

        protected override string GetContext()
        {
            if (_showHelp)
                return ProgramContext.Help;
            string context = _contextSelector();
            return context ?? ProgramContext.Help;
        }

        #region Help support
        private void IncludeHelpSupport()
        {
            var option = new ComplexOption(ConsoleProgramMessages.HelpOptionName)
            {
                ShortName = ConsoleProgramMessages.HelpOptionShortName,
                CaseSensitive = false,
                Order = 1,
                Handler = prms => _showHelp = true,
            };
            option.Usages[ProgramContext.Help].Requirement = OptionRequirement.Optional;
            Properties.Available.Options.Add(option);
        }

        private int HelpHandler()
        {
            DisplayUsage();
            return 0;
        }
        #endregion
    }

    public delegate string ContextSelector();
}